Skip to content

feat(differentials): polish search results UX and mobile compare bar#461

Merged
BigSimmo merged 16 commits into
mainfrom
claude/differentials-search-ux-polish-f2ff06
Jul 11, 2026
Merged

feat(differentials): polish search results UX and mobile compare bar#461
BigSimmo merged 16 commits into
mainfrom
claude/differentials-search-ux-polish-f2ff06

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Summary

  • Differentials search results polish across phone and desktop (single file: src/components/clinical-dashboard/differentials-home.tsx; structure preserved)
  • Phone: query/match-count header band now visible; best answer featured once (compact card, linked title, "Open page") instead of duplicated as the rank-1 card; safety-first callout added; source-status warning condensed to a slim strip with inline action
  • Compare on phones rebuilt as a floating FAB-style pill anchored above the bottom search dock: count badge, polite live region, and an explicit "Tick results to compare" empty state
  • Dead Sort/Filters buttons replaced with a working sort (Relevance / Urgency first / A–Z) on both breakpoints; rank numbers keep relevance order
  • Fixed desktop "Compare top 3" button that actually re-ran the source search; desktop compare CTA now shows a count badge or an empty-selection hint
  • Colour semantics: red reserved for emergent status badges (match labels use clinical accent; urgency rail no longer forces first row to emergent); selection toggles bumped to 44px tap targets

Verification

  • npm run verify:pr-local — script lands on main in CI: streamline risk-scoped PR verification #454 and does not exist on this branch; ran npm run verify:cheap (vitest 1449 passed / 1 skipped, lint, typecheck, runtime, action-pins, ci-scope, sitemap all green) plus npm run format:check (clean) instead

During development, use npm run verify:cheap as the faster iteration gate before the final PR-local preflight.

  • npm run verify:ui when UI, routing, styling, browser behavior, reduced-motion, or forced-colors behavior changed — in flight, will update this checklist with the result before merge; focused differentials Playwright specs (7 tests incl. 375px single-line-badge and horizontal-overflow checks) already pass on Chromium
  • npm run verify:release before release or handoff confidence claims — not a release
  • npm run eval:retrieval:quality — N/A: no retrieval, ranking, selection, chunking, or scoring change (the new sort is a client-side re-ordering of already-ranked catalogue results for display only)
  • npm run eval:rag -- --limit 15 + npm run eval:quality -- --rag-only — N/A: answer generation untouched
  • npm run check:production-readiness — N/A: no clinical workflow, privacy, env, Supabase, governance, or deployment behavior change
  • npm run check:deployment-readiness — N/A

Clinical Governance Preflight

Presentation-only change on a clinical decision-support surface; no data, ranking, access, or governance behavior touched.

  • Source-backed claims still require linked source verification before clinical use
  • No patient-identifiable document workflow was introduced or expanded without explicit governance approval
  • Supabase target remains Clinical KB Database (sjrfecxgysukkwxsowpy)
  • Service-role keys and private document access remain server-only
  • Demo/synthetic content remains clearly separated from real clinical sources
  • Source metadata, review status, and outdated/unknown-source behavior remain conservative
  • Deployment classification/TGA SaMD impact was checked when clinical decision-support behavior changed — no decision-support logic changed; red is now reserved for emergent-status badges, which keeps urgency signalling more conservative, not less

Notes

  • One known flake observed: ui-tools.spec.ts "differentials evidence-backed search badges stay single-line on narrow viewport" failed once under parallel workers (results view mount timeout upstream of this diff) and passed cleanly in isolation
  • Branch is behind main by CI: streamline risk-scoped PR verification #454/fix: harden Codex review auto-resolve flow #455 (CI/workflow changes, no file overlap with this diff); will merge main into the branch only if required checks or mergeability demand it

🤖 Generated with Claude Code

BigSimmo and others added 2 commits July 10, 2026 21:54
- Show the query/match-count header band on phones too, not just desktop
- Feature the best answer once on phones (compact card with Open page
  link) instead of duplicating it as the rank-1 list card
- Surface the safety-first callout on phones as a slim strip
- Condense the source-status warning into a single-row strip with an
  inline Run source search action
- Replace the dead Sort and Filters buttons with a working sort
  (relevance / urgency first / A-Z) on phones and desktop
- Fix the desktop "Compare top 3" button that actually re-ran the
  source search; it is now an honest Run source search action
- Rebuild the phone compare action as a floating FAB-style pill
  anchored above the bottom search dock, with a count badge, a
  polite live region, and an empty-selection hint state
- Reserve red for emergent status: match-quality labels now use the
  clinical accent, and the urgency rail no longer forces the first
  row to emergent
- Bump selection toggles to 44px tap targets

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@supabase

supabase Bot commented Jul 10, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The differentials search UI now supports client-side sorting, updated responsive result cards, source-status states, and floating mobile comparison. Selected comparison IDs propagate through presentation routes into workflow selection. UI tests and the branch review ledger are also updated.

Changes

Differentials search experience

Layer / File(s) Summary
Result sorting and state
src/components/clinical-dashboard/differentials-home.tsx
Adds relevance, urgency, and A–Z sorting with state resets when results change.
Responsive result rendering
src/components/clinical-dashboard/differentials-home.tsx
Updates badges, cards, tags, statuses, spacing, and breakpoint-specific result rendering.
Source status and responsive controls
src/components/clinical-dashboard/differentials-home.tsx
Adds evidence-check state handling and updates desktop/mobile source-status and sort controls.
Comparison URL flow
src/components/clinical-dashboard/differentials-home.tsx, src/app/differentials/presentations/..., src/components/differentials/differential-presentation-workflow-page.tsx, src/lib/differentials.ts
Propagates selected IDs through presentation URLs and applies them to the matching workflow candidates.
Validation and review records
tests/ui-smoke.spec.ts, tests/ui-tools.spec.ts, tests/differentials.test.ts, docs/branch-review-ledger.md
Updates navigation, route mocks, assertions, race coordination, typography expectations, workflow routing tests, comparison deep-link coverage, and review records.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SearchResultsView
  participant PresentationRoute
  participant WorkflowPage
  SearchResultsView->>PresentationRoute: open presentation URL with ids
  PresentationRoute->>WorkflowPage: pass selectedIds
  WorkflowPage->>WorkflowPage: mark matching candidates selected
Loading

Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Verification Claims ❌ Error The PR description says focused differentials Playwright specs 'already pass on Chromium' without naming the exact command/check and result. Rewrite verification notes as exact records, e.g. 'Ran npm run verify:ui: passed' or 'Not run: browser verification pending'.
Docstring Coverage ⚠️ Warning Docstring coverage is 6.25% which is insufficient. The required threshold is 70.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (9 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main UX polish and mobile compare bar changes.
Description check ✅ Passed The description follows the template with Summary, Verification, and Clinical Governance sections and includes the main relevant checklist context.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Generated And Sensitive Files ✅ Passed No committed secrets or local/generated artifacts found; the PR diff only touches source, tests, and docs, with no prohibited paths present.
Risky Git Or Deployment Actions ✅ Passed No touched file adds force-push/reset/delete/rebase/deploy guidance; the only doc change is a review-ledger row, and code/tests contain no risky-op instructions.
Supabase Project And Schema Safety ✅ Passed PR diff only touches docs/app/components/lib/tests; no .env.example, migrations, schema, RLS, or policy changes, and no stale Supabase project ref found.
Runtime And Package Manager Integrity ✅ Passed Diff vs origin/main touches only app/tests/docs; no package.json, lockfile, .npmrc, or engine/runtime settings changed, and Node 24/npm 11 enforcement remains intact.
Api Route Failure Handling ✅ Passed The route changes normalize/ignore invalid ids, return notFound for bad slugs, and fall back to a default workflow; no new API/provider failure path was added.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/differentials-search-ux-polish-f2ff06
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/differentials-search-ux-polish-f2ff06

Comment @coderabbitai help to get the list of available commands.

coderabbitai[bot]
coderabbitai Bot previously requested changes Jul 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/clinical-dashboard/differentials-home.tsx`:
- Around line 153-166: The comparison navigation in the mobile action and the
corresponding action near the desktop comparison controls only forwards the
query via routeWithQuery, dropping selectedIds. Update both Link/action
destinations to serialize the selected identifiers into the URL or shared
comparison state, and ensure the comparison page reads that same representation
so selections are preserved and produce distinct destinations.
- Around line 961-971: Distinguish unsearched from searched-with-no-results in
the source evidence panel. In the component using hasSourceEvidence, derive a
separate sourcesChecked state from evidenceIsCurrent and whether documentMatches
is defined, then update the conditional UI around the source-search button and
the related section around the additional referenced lines to show the
zero-match state after a current search instead of the initial-search prompt.
- Around line 557-571: Update the “Best answer” card styling in the component
containing this section so routine results use neutral or accent border,
background, and icon colors instead of danger tokens. Reserve danger styling for
emergent status indicators such as StatusBadge, while preserving the existing
compact/non-compact layout behavior.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 10487b7f-6e0b-4c4f-919e-089adc8b3bc0

📥 Commits

Reviewing files that changed from the base of the PR and between b32c17b and f7a3d95.

📒 Files selected for processing (2)
  • docs/production-readiness-checklist.md
  • src/components/clinical-dashboard/differentials-home.tsx

Comment thread src/components/clinical-dashboard/differentials-home.tsx
Comment thread src/components/clinical-dashboard/differentials-home.tsx
Comment thread src/components/clinical-dashboard/differentials-home.tsx Outdated
@BigSimmo
BigSimmo enabled auto-merge (squash) July 10, 2026 20:08
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 1 file(s) based on 3 unresolved review comments.

Files modified:

  • src/components/clinical-dashboard/differentials-home.tsx

Commit: 0dca40a27af0bd6e25f48e65386fc15d8a601dab

The changes have been pushed to the claude/differentials-search-ux-polish-f2ff06 branch.

Time taken: 7m 35s

Fixed 1 file(s) based on 3 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
@BigSimmo

Copy link
Copy Markdown
Owner Author

@codex, fix all failing CI testing

@chatgpt-codex-connector

Copy link
Copy Markdown

Summary

Testing

  • npm ci
  • npm run format:check
  • npm run lint
  • npm run typecheck
  • npm run test:coverage — 151 test files passed / 1 skipped; 1411 tests passed / 1 skipped.
  • npm audit --omit=dev --audit-level=high — 0 vulnerabilities.
  • npm run check:runtime
  • npm run check:github-actions
  • npm run check:codex-autofix-workflow
  • npm run check:edge:functions — script exited successfully with local Deno-missing skip message; CI installs Deno v2.x.
  • npm run check:production-readiness:ci — CI-safe readiness check passed with non-blocking missing-secret warnings.
  • ⚠️ npm run build — failed locally because next/font could not fetch Geist / Geist Mono from fonts.gstatic.com in this environment.

View task →

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9ff60bc5bd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/clinical-dashboard/differentials-home.tsx

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bd6642dc8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/app/differentials/presentations/page.tsx Outdated
Comment thread tests/ui-smoke.spec.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ce84c4b22f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/clinical-dashboard/differentials-home.tsx
@BigSimmo
BigSimmo dismissed coderabbitai[bot]’s stale review July 11, 2026 08:58

All actionable threads are resolved on the current head; dismissing the stale blocking review for verified merge readiness.

coderabbitai[bot]
coderabbitai Bot previously requested changes Jul 11, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/ui-smoke.spec.ts (1)

277-283: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not turn invalid answer requests into valid mock requests.

src/app/api/answer/route.ts:32-80 requires a trimmed, non-empty query with a maximum length of 2000. Falling back to "What monitoring is required?" lets malformed client payloads receive a successful mock response, so smoke tests can miss a broken /api/answer request contract.

Validate the query and fail the mock when it is absent, blank, or oversized.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/ui-smoke.spec.ts` around lines 277 - 283, Update the request handling
around the `body.query` extraction and `onAnswerRequest` in the smoke-test route
mock to validate that `query` is present, trimmed, non-empty, and no longer than
2000 characters; fail the mock for invalid values instead of substituting the
default question, while preserving valid query handling.
🧹 Nitpick comments (1)
src/components/differentials/differential-presentation-workflow-page.tsx (1)

596-613: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Minor: redundant double iteration over candidates.

baseWorkflow.candidates is iterated twice — once via .map(...) to set selected, once via .filter(...).length to compute selectedCount. Could be combined into a single pass, but with typically small candidate lists this has negligible practical impact.

♻️ Optional consolidation
-  const workflow = requestedIds.size
-    ? {
-        ...baseWorkflow,
-        candidates: baseWorkflow.candidates.map((candidate) => ({
-          ...candidate,
-          selected: requestedIds.has(candidate.slug),
-        })),
-        selectedCount: baseWorkflow.candidates.filter((candidate) => requestedIds.has(candidate.slug)).length,
-      }
-    : baseWorkflow;
+  const workflow = requestedIds.size
+    ? (() => {
+        const candidates = baseWorkflow.candidates.map((candidate) => ({
+          ...candidate,
+          selected: requestedIds.has(candidate.slug),
+        }));
+        return {
+          ...baseWorkflow,
+          candidates,
+          selectedCount: candidates.filter((candidate) => candidate.selected).length,
+        };
+      })()
+    : baseWorkflow;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/differentials/differential-presentation-workflow-page.tsx`
around lines 596 - 613, Consolidate the `baseWorkflow.candidates` processing in
the workflow construction into a single pass, deriving both the mapped
candidates with `selected` flags and `selectedCount` together. Preserve the
existing behavior for empty `requestedIds` and the current selection matching
via `requestedIds.has(candidate.slug)`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/ui-smoke.spec.ts`:
- Around line 1866-1877: Update the route fulfillment handling in the request
mock so failures are ignored only for the expected aborted first request.
Preserve the catch for the delayed response when currentRequest equals 1, but
rethrow fulfillment errors for currentRequest greater than 1 so the current
response must reach the page.
- Around line 1890-1891: Replace the fixed waitForTimeout in the source-status
test with an explicit wait for the relevant response or route-completion signal,
then assert sourceStatus contains the final “Not yet checked” state. Preserve
the existing assertion and synchronize on the actual operation completing rather
than elapsed time.

---

Outside diff comments:
In `@tests/ui-smoke.spec.ts`:
- Around line 277-283: Update the request handling around the `body.query`
extraction and `onAnswerRequest` in the smoke-test route mock to validate that
`query` is present, trimmed, non-empty, and no longer than 2000 characters; fail
the mock for invalid values instead of substituting the default question, while
preserving valid query handling.

---

Nitpick comments:
In `@src/components/differentials/differential-presentation-workflow-page.tsx`:
- Around line 596-613: Consolidate the `baseWorkflow.candidates` processing in
the workflow construction into a single pass, deriving both the mapped
candidates with `selected` flags and `selectedCount` together. Preserve the
existing behavior for empty `requestedIds` and the current selection matching
via `requestedIds.has(candidate.slug)`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d3c6ef7e-9393-461a-88f7-77f46f3b7616

📥 Commits

Reviewing files that changed from the base of the PR and between f7a3d95 and ce84c4b.

📒 Files selected for processing (7)
  • docs/branch-review-ledger.md
  • src/app/differentials/presentations/[slug]/page.tsx
  • src/app/differentials/presentations/page.tsx
  • src/components/clinical-dashboard/differentials-home.tsx
  • src/components/differentials/differential-presentation-workflow-page.tsx
  • tests/ui-smoke.spec.ts
  • tests/ui-tools.spec.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/branch-review-ledger.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/clinical-dashboard/differentials-home.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/ui-smoke.spec.ts (1)

277-283: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not turn invalid answer requests into valid mock requests.

src/app/api/answer/route.ts:32-80 requires a trimmed, non-empty query with a maximum length of 2000. Falling back to "What monitoring is required?" lets malformed client payloads receive a successful mock response, so smoke tests can miss a broken /api/answer request contract.

Validate the query and fail the mock when it is absent, blank, or oversized.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/ui-smoke.spec.ts` around lines 277 - 283, Update the request handling
around the `body.query` extraction and `onAnswerRequest` in the smoke-test route
mock to validate that `query` is present, trimmed, non-empty, and no longer than
2000 characters; fail the mock for invalid values instead of substituting the
default question, while preserving valid query handling.
🧹 Nitpick comments (1)
src/components/differentials/differential-presentation-workflow-page.tsx (1)

596-613: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Minor: redundant double iteration over candidates.

baseWorkflow.candidates is iterated twice — once via .map(...) to set selected, once via .filter(...).length to compute selectedCount. Could be combined into a single pass, but with typically small candidate lists this has negligible practical impact.

♻️ Optional consolidation
-  const workflow = requestedIds.size
-    ? {
-        ...baseWorkflow,
-        candidates: baseWorkflow.candidates.map((candidate) => ({
-          ...candidate,
-          selected: requestedIds.has(candidate.slug),
-        })),
-        selectedCount: baseWorkflow.candidates.filter((candidate) => requestedIds.has(candidate.slug)).length,
-      }
-    : baseWorkflow;
+  const workflow = requestedIds.size
+    ? (() => {
+        const candidates = baseWorkflow.candidates.map((candidate) => ({
+          ...candidate,
+          selected: requestedIds.has(candidate.slug),
+        }));
+        return {
+          ...baseWorkflow,
+          candidates,
+          selectedCount: candidates.filter((candidate) => candidate.selected).length,
+        };
+      })()
+    : baseWorkflow;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/differentials/differential-presentation-workflow-page.tsx`
around lines 596 - 613, Consolidate the `baseWorkflow.candidates` processing in
the workflow construction into a single pass, deriving both the mapped
candidates with `selected` flags and `selectedCount` together. Preserve the
existing behavior for empty `requestedIds` and the current selection matching
via `requestedIds.has(candidate.slug)`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/ui-smoke.spec.ts`:
- Around line 1866-1877: Update the route fulfillment handling in the request
mock so failures are ignored only for the expected aborted first request.
Preserve the catch for the delayed response when currentRequest equals 1, but
rethrow fulfillment errors for currentRequest greater than 1 so the current
response must reach the page.
- Around line 1890-1891: Replace the fixed waitForTimeout in the source-status
test with an explicit wait for the relevant response or route-completion signal,
then assert sourceStatus contains the final “Not yet checked” state. Preserve
the existing assertion and synchronize on the actual operation completing rather
than elapsed time.

---

Outside diff comments:
In `@tests/ui-smoke.spec.ts`:
- Around line 277-283: Update the request handling around the `body.query`
extraction and `onAnswerRequest` in the smoke-test route mock to validate that
`query` is present, trimmed, non-empty, and no longer than 2000 characters; fail
the mock for invalid values instead of substituting the default question, while
preserving valid query handling.

---

Nitpick comments:
In `@src/components/differentials/differential-presentation-workflow-page.tsx`:
- Around line 596-613: Consolidate the `baseWorkflow.candidates` processing in
the workflow construction into a single pass, deriving both the mapped
candidates with `selected` flags and `selectedCount` together. Preserve the
existing behavior for empty `requestedIds` and the current selection matching
via `requestedIds.has(candidate.slug)`.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d3c6ef7e-9393-461a-88f7-77f46f3b7616

📥 Commits

Reviewing files that changed from the base of the PR and between f7a3d95 and ce84c4b.

📒 Files selected for processing (7)
  • docs/branch-review-ledger.md
  • src/app/differentials/presentations/[slug]/page.tsx
  • src/app/differentials/presentations/page.tsx
  • src/components/clinical-dashboard/differentials-home.tsx
  • src/components/differentials/differential-presentation-workflow-page.tsx
  • tests/ui-smoke.spec.ts
  • tests/ui-tools.spec.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/branch-review-ledger.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/clinical-dashboard/differentials-home.tsx
🛑 Comments failed to post (2)
tests/ui-smoke.spec.ts (2)

1866-1877: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Do not swallow fulfillment failures for the current response.

The delayed first request may legitimately be aborted after the URL changes, but .catch(() => undefined) also hides failures for later/current responses. The test can therefore pass after incrementing requestCount even though the response being tested never reaches the page. Catch only the expected stale-request abort and rethrow failures for currentRequest > 1.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/ui-smoke.spec.ts` around lines 1866 - 1877, Update the route
fulfillment handling in the request mock so failures are ignored only for the
expected aborted first request. Preserve the catch for the delayed response when
currentRequest equals 1, but rethrow fulfillment errors for currentRequest
greater than 1 so the current response must reach the page.

1890-1891: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Synchronize on response completion instead of using a fixed sleep.

waitForTimeout(600) assumes the delayed response and subsequent React/router update complete within a 100ms margin. That can remain flaky under CI load. Wait for an explicit route/response completion signal, then assert the final source-status state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/ui-smoke.spec.ts` around lines 1890 - 1891, Replace the fixed
waitForTimeout in the source-status test with an explicit wait for the relevant
response or route-completion signal, then assert sourceStatus contains the final
“Not yet checked” state. Preserve the existing assertion and synchronize on the
actual operation completing rather than elapsed time.

@BigSimmo
BigSimmo disabled auto-merge July 11, 2026 10:30
BigSimmo added 3 commits July 11, 2026 18:55
# Conflicts:
#	docs/branch-review-ledger.md
#	tests/ui-smoke.spec.ts
#	tests/ui-tools.spec.ts
# Conflicts:
#	docs/branch-review-ledger.md
@BigSimmo
BigSimmo dismissed coderabbitai[bot]’s stale review July 11, 2026 11:06

All actionable findings fixed in 9d9d2cb: strict answer mock validation, current-response fulfillment propagation and explicit synchronization, workflow-aware selection routing, diagnosis-only comparison controls, and restored required smoke coverage. The low-value candidate iteration was also consolidated.

@BigSimmo

Copy link
Copy Markdown
Owner Author

Resolved the remaining review set in 9d9d2cb0a: workflow-aware comparison routing, diagnosis-only selection controls, restored @critical anonymous-search coverage, strict answer mock validation, explicit current-response synchronization, and single-pass selected-count derivation. Focused tests pass 38/38 with typecheck and formatting clean.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/lib/differentials.ts (1)

78-95: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

"Best match" selection favors raw overlap count over specificity.

matchCount is a raw count of matched candidates with no normalization by presentation.candidates.length. A workflow with many candidates that happens to include a couple of the requested slugs will out-rank a smaller, more precise workflow whose candidates are exactly the requested ids. Ties are also silently broken by catalog iteration order with no documented rationale. Since src/app/differentials/presentations/page.tsx routes users directly based on this result, a less relevant workflow could win.

Consider weighting by match ratio (e.g., matchCount / presentation.candidates.length) or preferring the presentation that fully covers requestedIds before falling back to raw count.

♻️ Possible refactor to prefer specificity
   let bestMatch: DifferentialPresentationWorkflow | null = null;
-  let bestMatchCount = 0;
+  let bestScore = 0;
   for (const presentation of differentialPresentations()) {
     const matchCount = presentation.candidates.reduce(
       (count, candidate) => count + (requestedIds.has(candidate.slug) ? 1 : 0),
       0,
     );
-    if (matchCount > bestMatchCount) {
+    if (matchCount === 0) continue;
+    const score = matchCount / presentation.candidates.length;
+    if (score > bestScore) {
       bestMatch = presentation;
-      bestMatchCount = matchCount;
+      bestScore = score;
     }
   }
   return bestMatch;

Please confirm whether raw-count ranking (vs. specificity-weighted) is the intended semantics here before deciding to change it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/differentials.ts` around lines 78 - 95, Confirm the intended ranking
semantics for getPresentationWorkflowForDiagnosisIds before changing
implementation. If specificity is intended, rank presentations by match ratio
(matchCount divided by presentation.candidates.length) or prioritize workflows
fully covering requestedIds, and define a deterministic tie-breaker instead of
relying on differentialPresentations() iteration order.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/lib/differentials.ts`:
- Around line 78-95: Confirm the intended ranking semantics for
getPresentationWorkflowForDiagnosisIds before changing implementation. If
specificity is intended, rank presentations by match ratio (matchCount divided
by presentation.candidates.length) or prioritize workflows fully covering
requestedIds, and define a deterministic tie-breaker instead of relying on
differentialPresentations() iteration order.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 449bd2c2-6217-447e-b466-697f6ad0af56

📥 Commits

Reviewing files that changed from the base of the PR and between 5e31387 and 9d9d2cb.

📒 Files selected for processing (7)
  • docs/branch-review-ledger.md
  • src/app/differentials/presentations/page.tsx
  • src/components/clinical-dashboard/differentials-home.tsx
  • src/components/differentials/differential-presentation-workflow-page.tsx
  • src/lib/differentials.ts
  • tests/differentials.test.ts
  • tests/ui-smoke.spec.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/branch-review-ledger.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/app/differentials/presentations/page.tsx
  • src/components/differentials/differential-presentation-workflow-page.tsx
  • src/components/clinical-dashboard/differentials-home.tsx

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 99432010d1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/app/differentials/presentations/page.tsx Outdated
@BigSimmo

Copy link
Copy Markdown
Owner Author

Follow-up edge case resolved in 5e34f024a: cross-workflow selections are intersected with the chosen presentation candidate set before redirect. Focused differential tests pass 22/22 and typecheck/formatting are clean.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5e34f024ab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/ui-smoke.spec.ts Outdated
@BigSimmo

Copy link
Copy Markdown
Owner Author

Required-gate marker audit completed in 8bf455325: restored @critical to all four core smoke tests removed by the branch (tablet navigation, source-backed answer, prescribing routes, and viewer search).

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Autofix skipped. No unresolved CodeRabbit review comments with fix instructions found.

@BigSimmo
BigSimmo merged commit 0c76030 into main Jul 11, 2026
16 checks passed
@BigSimmo
BigSimmo deleted the claude/differentials-search-ux-polish-f2ff06 branch July 11, 2026 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants